/*
* 棋子分黑白两方
*/ 
var Role = {
    Black: 0,
    White: 1
};


/*
* 三子棋的游戏环境
*/
class Env {
    constructor() {
        this.reset();
    }

    reset() {
        this.state = '□□□□□□□□□'.split('');
    }

    getState() {
        if(arguments.length === 1) {
            let role = arguments[0];
            let o = role === Role.Black ? '1' : '2';
            let x = role === Role.Black ? '2' : '1';
            return this.state.join('').replace(/□/g, '0').replace(/○/g, o).replace(/×/g, x);
        }
        else return this.state.join('');
    }

    setState(role, state) {
        let enemy = role === Role.White ? '×' : '○';
        let me = role === Role.White ? '○' : '×';
        this.state = state.replace(/1/g, enemy).replace(/2/g, me).replace(/0/g, '□').split('');
    }

    getStateAt(x, y) {
        let chess = this.state[x + y * 3];
        if (chess === '□') 
            return null;
        if (chess === '○')
            return Role.White;
        if (chess === '×')
            return Role.Black;
    }

    // 对当前状态进行评分，分值在-1~1之间
    getReward(role, state) {
        let enemy = role === Role.Black ? Role.White : Role.Black;
        state = state || this.state;
        if (this.win(role, state)) 
            return 1;
        if (this.win(enemy, state))
            return -1;
        return 0;
    }

    /* 
    * 落子
    */
    play(role, action) {
        console.assert(this.getNextRole() == role);
        // 落子处必须无子
        console.assert(this.state[action] === '□');
        this.state[action] = role == Role.Black ? '×' : '○';
        return {
            gameOver: this.win(role) || this.getChessCount() === 9,
            reward: this.getReward(role),
            action: action,
            state: this.state,
        }
    }

    getActionSpace() {
        // 一共有9个落子位置
        return [0, 1, 2, 3, 4, 5, 6, 7, 8];
    }

    getAvailableActions() {
        let actions = [];
        for (let i = 0; i < 9; i++) {
            if (this.state[i] === '□')
                actions.push(i);
        }
        return actions;
    }

    actionAvailable(action) {
        return this.state[action] === '□';
    }

    getNextRole() {
        let blackCount = 0;
        let whiteCount = 0;
        for (let i = 0; i < 9; i++) {
            let c = this.state[i];
            if (c === '×') 
                blackCount++;
            else if (c === '○')
                whiteCount++;
        }
        return blackCount > whiteCount ? Role.White : Role.Black;
    }

    /*
    * 判断某方是否获胜
    */
    win(role, state) {
        state = state || this.state;
        let arr = [
            [0, 1, 2], [3, 4, 5], [6, 7, 8],
            [0, 3, 6], [1, 4, 7], [2, 5, 8],
            [0, 4, 8], [2, 4, 6]
        ]
        let chess = role === Role.Black ? '×' : '○';
        let template = chess + chess + chess;
        for (let i = 0; i < arr.length; i++) {
            let s = state[arr[i][0]] + state[arr[i][1]] + state[arr[i][2]];
            if (s === template)
                return true;
        }
        return false;
    }

    getGameResult(role) {
        let enemy = role === Role.Black ? Role.White : Role.Black;
        if (this.win(role))
            return 'win';
        if (this.win(enemy))
            return 'lose';
        if (this.getChessCount() == 9)
            return 'draw';
        return null;
    }

    getChessCount() {
        let sum = 0;
        for (let i = 0; i < 9; i++)
            if (this.state[i] != '□')
                sum++;
        return sum;
    }
}
